package xyz.xcvu.ma2.module;

import org.springframework.stereotype.Component;
import org.ssssssss.magicapi.core.annotation.MagicModule;
import org.ssssssss.script.annotation.Comment;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

import javax.servlet.http.HttpServletRequest;

/**
 * 字符串工具类
 * @author hyz
 *
 */
@Component
@MagicModule("str")
public class StringUtil {

    private static final String[] HanDigitStr = new String[] {
            "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"
    };

    private static final String[] HanDiveStr = new String[] {
            "", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "兆",
            "拾", "佰", "仟", "万兆", "拾", "佰", "仟", "亿兆", "拾", "佰", "仟"
    };

    @Comment("将首字母变大写")
    public static String toFirstUp(@Comment("字符串") String str){
        return str.length() <= 1 ? str.toUpperCase() : String.valueOf(str.charAt(0)).toUpperCase() + str.substring(1);
    }

    @Comment("将首字母变小写")
    public static String toFirstLow(@Comment("字符串") String str){
        return str.length() <= 1 ? str.toLowerCase() :String.valueOf(str.charAt(0)).toLowerCase() + str.substring(1);
    }

    @Comment("将数组转换成一个分隔符连接的字符串")
    public static String concatStr(@Comment("字符串数组") String[] str, @Comment("分隔符字符串") String split){
        if(str == null || str.length == 0){
            return "";
        }
        StringBuffer buf = new StringBuffer();
        for(String s :str){
            buf.append(s+split);
        }
        buf.delete(buf.lastIndexOf(split),buf.length());
        return buf.toString();
    }

    @Comment("将字符串数组转换成一个分隔符连接的字符串  并且包含前缀后缀 比如单引号")
    public static String concatStr(@Comment("字符串数组") String[] str, @Comment("分隔符") String split, @Comment("前后缀") String preSuffix){
        if(str == null || str.length == 0){
            return "";
        }
        StringBuffer buf = new StringBuffer();
        for(String s :str){
            buf.append(preSuffix).append(s).append(preSuffix).append(split);
        }
        buf.delete(buf.lastIndexOf(split),buf.length());
        return buf.toString();
    }

    @Comment("将Long数组通过分隔符连接为字符串")
    public static String concatStr(@Comment("数组") Long[] str, @Comment("分隔符") String split){
        if(str == null || str.length == 0){
            return "";
        }
        StringBuffer buf = new StringBuffer();
        for(Long s :str){
            buf.append(s+split);
        }
        buf.delete(buf.lastIndexOf(split),buf.length());
        return buf.toString();
    }

    @Comment("将集合通过分隔符连接为字符串")
    public static String concatStr(@Comment("集合") Collection<?> str, @Comment("分隔符") String split){
        if(str == null || str.size() == 0){
            return "";
        }
        StringBuffer buf = new StringBuffer();
        for(Object s :str){
            buf.append(s+split);
        }
        buf.delete(buf.lastIndexOf(split),buf.length());
        return buf.toString();
    }

    @Comment("将集合通过分隔符连接为字符串并带有前后缀")
    public static String concatStr(@Comment("集合") Collection<?> str, @Comment("分隔符") String split, @Comment("前后缀") String preSuffix){
        if(str == null || str.size() == 0){
            return "";
        }
        StringBuffer buf = new StringBuffer();
        for(Object s :str){
            buf.append(preSuffix).append(s).append(preSuffix).append(split);
        }
        buf.delete(buf.lastIndexOf(split),buf.length());
        return buf.toString();
    }

    @Comment("将字符串通过分隔符转换为数组")
    public static String[] splitStr(@Comment("字符串") String str, @Comment("分隔符") String split){
        if(str == null || str.equals("")){
            return new String[]{};
        }
        return str.split(split);
    }

    public static String format2Z(String str){
        return to$(str).replaceAll("￥", "");
    }

    public static String toPercent(String str){
        return to$(str).replaceAll("￥", "") + "%";
    }

    public static String to2Z(String str){
        return to$(str).replaceAll("￥|,", "");
    }

    @Comment("将字符串转换成金额的格式")
    public static String to$(@Comment("数字字符串") String str){
        if(str == null || str.equals("")){
            return "￥0.00";
        }
        if(str.lastIndexOf(".") <= 0){
            //不含小数点
            str = addStr$(str) + ".00";
        }else{
            //含小数点
            String top = str.substring(0,str.indexOf("."));//整数部分

            if(top.length() > 1 && top.charAt(0) == '0'){
                top = top.substring(1,top.length());
            }

            String end = str.substring(str.indexOf(".") + 1,str.length());//小数部分

            if(end.length() > 2){
                end = end.substring(0,2);
            }else if(end.length() == 1){
                end = end + "0";
            }else if(end.length() == 0){
                end = end + "00";
            }

            str = addStr$(top) + "." + end;
        }

        return "￥" + str;
    }

    @Comment("数字字符串添加千分位分隔符")
    private static String addStr$(@Comment("数字字符串") String str){
        String buf = "";
        while(true){
            if(str.length() <=3){
                break;
            }
            buf = "," + str.substring(str.length() - 3,str.length()) + buf;

            str = str.substring(0,str.length() - 3);
        }
        buf = str + buf;
        if(buf.indexOf(",") == 0 ){
            buf = buf.substring(1,buf.length());
        }

        return buf;
    }

    @Comment("将字符串数组 转换成List")
    public static List<String> toList(@Comment("字符串数组") String[] ars){
        List<String> list = new ArrayList<String>();
        if(ars != null){
            for(String s : ars){
                list.add(s);
            }
        }
        return list;
    }

    @Comment("将List转换成Array")
    public static String[] toArray(@Comment("集合") Collection<String> list){
        String[] ars = new String[list.size()];
        if(list != null){
            int i=0;
            for(String s : list){
                ars[i++] = s;
            }
        }
        return ars;
    }

    @Comment("添加字符串数组到由分隔符组成的字符串中a,b,c + d,e => a,b,c,d,e")
    public static String appendStrList(@Comment("源字符串") String src, @Comment("分隔符") String split, @Comment("添加的字符串数组") String[] target){
        if(src !=null && src.length()>0){
            src = src + split;
        }
        return src + StringUtil.concatStr(target, split);
    }

    @Comment("添加字符串到由分隔符组成的字符串中a,b,c + d => a,b,c,d")
    public static String appendStr(@Comment("源字符串") String src, @Comment("分隔符") String split, @Comment("添加的字符串") String str){
        if(src !=null && src.length()>0){
            src = src + split;
        }
        return src + str;
    }

    @Comment("移除由分隔符组成的字符串中的指定字符串数组")
    public static String removeStrList(@Comment("源字符串") String src, @Comment("分隔符") String split, @Comment("字符串数组") String[] strList){
        String[] arr = StringUtil.splitStr(src, split);
        List<String> list = toList(arr);
        list.removeAll(Arrays.asList(strList));
        return StringUtil.concatStr(toArray(list),split);
    }

    @Comment("移除由分隔符组成的字符串中的指定字符串")
    public static String removeStr(@Comment("源字符串") String src, @Comment("分隔符") String split, @Comment("移除的字符串") String str){
        String[] arr = StringUtil.splitStr(src, split);
        List<String> list = toList(arr);
        list.remove(str);
        return StringUtil.concatStr(toArray(list),split);
    }

    @Comment("获取为字符串")
    public static String getStr(String str){
        return str == null ? "" : str;
    }
    @Comment("转换为字符串")
    public static String getStr(Object str){
        return str == null ? "" : str.toString();
    }

    @Comment("规则:如果第二个字母是大写,则不变;如果第二个字母是小写,将第一个字母变成大写。abcCCC ==>> AbcCCC;ABCDdd==>> ABCDdd")
    public static String getMethodNameByFieldName(@Comment("字段名（小驼峰）") String fieldName){
        if(fieldName.length() > 1 && fieldName.charAt(1) >= 'A' && fieldName.charAt(1) <= 'Z'){
            return fieldName;
        }else{
            return toFirstUp(fieldName);
        }
    }

    @Comment("规则:如果第二个字母是大写,则不变;如果第二个字母是小写,将第一个字母变成小写。Name =>> name；ABS =>> ABS")
    public static String getFieldNameByMethodName(@Comment("方法名（大驼峰）") String methodName){
        if(methodName.length() > 1 && methodName.charAt(1) >= 'A' && methodName.charAt(1) <= 'Z'){
            return methodName;
        }else{
            return toFirstLow(methodName);
        }
    }

    @Comment("小驼峰转大写下划线")
    public static String toSqlColumn(@Comment("小驼峰字符串") String name){
        StringBuffer sqlColumn = new StringBuffer();
        char[] array = name.toCharArray();
        for(int i=0;i<array.length;i++){
            char c = array[i];
            sqlColumn.append(String.valueOf(c).toUpperCase());
            if(i != array.length-1){
                char nextC = array[i+1];
                if((c>='a' && c<='z' && nextC>='A' && nextC<='Z') && !(nextC>='a' && nextC<='z' && c>='A' && c<='Z')){
                    sqlColumn.append("_");
                }
            }
        }
        return sqlColumn.toString();
    }

    @Comment("列名称转字段名（下划线转小驼峰）")
    public static String toFieldColumn(@Comment("列名称") String columnName){
        columnName = columnName.toLowerCase();
        StringBuffer name = new StringBuffer();
        char[] array = columnName.toCharArray();
        for(int i=0;i<array.length;i++){
            char c = array[i];
            if(c == '_' && array.length>i+1){
                i++;
                name.append((array[i]+"").toUpperCase());
            }else{
                name.append(array[i]);
            }
        }
        return name.toString();
    }

    @Comment("判断字符串数组是否包含指定字符串")
    public static boolean contains(@Comment("字符串数组") String[] arr, @Comment("字符串") String str){
        for(String s : arr){
            if(s.equals(str)){
                return true;
            }
        }
        return false;
    }

    @Comment("如果不包含目标字符串就添加到源字符串数组")
    public static String[] notContainsAdd(@Comment("源字符串数组") String[] arr, @Comment("目标字符串") String str){
        if(!contains(arr, str)){
            String[] _newArr = new String[arr.length + 1];
            for(int i=0;i<arr.length;i++){
                _newArr[i] = arr[i];
            }
            _newArr[arr.length] = str;
            arr = _newArr;
        }
        return arr;
    }

    @Comment("源字符串数组如果包含就去除目标字符串")
    public static String[] containsRemove(@Comment("源字符串数组") String[] arr, @Comment("目标字符串") String str){
        List<String> list = new ArrayList<String>();
        for(String s :arr){
            if(s.equals(str)){
                continue;
            }
            list.add(s);
        }
        return toArray(list);
    }

    @Comment("去除数字字符串多余的0")
    public static String removeLastZero(@Comment("数字字符串") String str){
        if(str.contains(".")&&str.endsWith("0")){
            str = str.replaceAll("0+$", "");
            if(str.endsWith(".")){
                str = str.replaceAll("\\.", "");
            }
        }
        return str;
    }

    @Comment("求两个字符串数组的并集")
    public static String[] combineArr(@Comment("字符串数组一") String[] arr1, @Comment("字符串数组二") String[] arr2){
        Set<String> set = new HashSet<String>();
        for(String s : arr1){
            set.add(s);
        }
        for(String s : arr2){
            set.add(s);
        }
        return toArray(set);
    }

    @Comment("求两个字符串数组的交集")
    public static String[] retains(@Comment("字符串数组一") String[] arr1, @Comment("字符串数组二") String[] arr2){
        List<String> list1 = toList(arr1);
        List<String> list2 = toList(arr2);
        list1.retainAll(list2);
        return toArray(list1);
    }

    @Comment("去除字符串多余的空格")
    public static String trim(@Comment("字符串") String str){
        if(str == null){
            return "";
        }
        return str.trim();
    }

    @Comment("设置字符串前导字符")
    public static String getAddCode(@Comment("源字符串") String source, @Comment("添加的前缀") String addStr, @Comment("前缀长度") int len) {
        if (source == null) {
            return "";
        }
        StringBuffer _rtn = new StringBuffer(100);
        if (source.length() < len) {
            for (int i = 0; i < len - source.length(); i++) {
                _rtn.append(addStr);
            }
            return _rtn + source;
        } else {
            return source;
        }
    }

    @Comment("将货币转换为大写形式(类内部调用)")
    private static String PositiveIntegerToHanStr(@Comment("正整数字符串") String NumStr) {
        // 输入字符串必须正整数，只允许前导空格(必须右对齐)，不宜有前导零
        String RMBStr = "";
        boolean lastZero = false;
        boolean hasValue = false; // 亿、万进位前有数值标记
        int len, n;
        len = NumStr.length();
        if (len > 15) {
            return "数值过大!";
        }
        for (int i = len - 1; i >= 0; i--) {
            if (NumStr.charAt(len - i - 1) == ' ') {
                continue;
            }
            n = NumStr.charAt(len - i - 1) - '0';
            if (n < 0 || n > 9) {
                return "输入含非数字字符!";
            }

            if (n != 0) {
                if (lastZero) {
                    RMBStr += HanDigitStr[0]; // 若干零后若跟非零值，只显示一个零
                }
                // 除了亿万前的零不带到后面
                // if( !( n==1 && (i%4)==1 && (lastZero || i==len-1) ) )
                // 如十进位前有零也不发壹音用此行
                if (!(n == 1 && (i % 4) == 1 && i == len - 1)) // 十进位处于第一位不发壹音
                {
                    RMBStr += HanDigitStr[n];
                }
                RMBStr += HanDiveStr[i]; // 非零值后加进位，个位为空
                hasValue = true; // 置万进位前有值标记

            } else {
                if ((i % 8) == 0 || ((i % 8) == 4 && hasValue)) // 亿万之间必须有非零值方显示万
                {
                    RMBStr += HanDiveStr[i]; // “亿”或“万”
                }
            }
            if (i % 8 == 0) {
                hasValue = false; // 万进位前有值标记逢亿复位
            }
            lastZero = (n == 0) && (i % 4 != 0);
        }

        if (RMBStr.length() == 0) {
            return HanDigitStr[0]; // 输入空字符或"0"，返回"零"
        }
        return RMBStr;
    }

    @Comment("将货币转换为大写形式")
    public static String numToRMBStr(@Comment("传入的数据") double val) {
        String SignStr = "";
        String TailStr = "";
        long fraction, integer;
        int jiao, fen;

        if (val < 0) {
            val = -val;
            SignStr = "负";
        }
        if (val > 99999999999999.999 || val < -99999999999999.999) {
            return "数值位数过大!";
        }
        // 四舍五入到分
        long temp = Math.round(val * 100);
        integer = temp / 100;
        fraction = temp % 100;
        jiao = (int) fraction / 10;
        fen = (int) fraction % 10;
        if (jiao == 0 && fen == 0) {
            TailStr = "整";
        } else {
            TailStr = HanDigitStr[jiao];
            if (jiao != 0) {
                TailStr += "角";
            }
            // 零元后不写零几分
            if (integer == 0 && jiao == 0) {
                TailStr = "";
            }
            if (fen != 0) {
                TailStr += HanDigitStr[fen] + "分";
            }
        }
        // 下一行可用于非正规金融场合，0.03只显示“叁分”而不是“零元叁分”
        // if( !integer ) return SignStr+TailStr;
        return SignStr + PositiveIntegerToHanStr(String.valueOf(integer)) + "元" + TailStr;
    }

    @Comment("对文件流输出下载的中文文件名进行编码 屏蔽各种浏览器版本的差异性")
    public static String encodeChineseDownloadFileName(@Comment("请求体") HttpServletRequest request, @Comment("文件名称") String pFileName) {
        String agent = request.getHeader("USER-AGENT");
        try {
            if (null != agent && -1 != agent.indexOf("MSIE")) {
                pFileName = URLEncoder.encode(pFileName, "utf-8");
            } else {
                pFileName = new String(pFileName.getBytes("utf-8"), "iso8859-1");
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return pFileName;
    }

}
